/**
 * @particulars Vue 的初始化
 */

import { compilerToFunction } from "./compiler";
import { callHook, mountComponent } from "./lifecycle";
import { initState } from "./state";
import { mergeOptions } from "./utils";

// 1、在Vue 原型上扩展_init 方法
export function initMixin(Vue) {
  // 1-1、用于初始化操作
  Vue.prototype._init = function (options) {
    const vm = this;

    // 将用户的选项和Vue 的全局选项进行合并挂载到实例上的$options
    // this.constructor 指向Vue 的构造函数，this.constructor.options 指向挂载到Vue 上的全局options
    vm.$options = mergeOptions(this.constructor.options, options);

    // 依次执行beforeCreate
    callHook(vm, 'beforeCreate');
    // 初始化状态数据，初始化计算属性，watch 等等...
    initState(vm);

    callHook(vm, 'created');
    // 实现数据的挂载
    if (options.el) vm.$mount(options.el);
  }

  // 1-2、用于挂载数据
  Vue.prototype.$mount = function (el) {
    const vm = this;
    const opts = vm.$options;
    el = document.querySelector(el);

    // 先进行查找是否有render 函数
    if (!opts.render) {
      // 选项中是否有template，有直接使用，没有就使用el
      let template;
      if (!opts.template && el) {
        template = el.outerHTML;
      } else {
        template = opts.template;
      }

      // 对模板进行编译，将模板转成语法树，并在实例选项中挂载render 函数
      if (template) {
        const render = compilerToFunction(template);
        opts.render = render;
      }
    }

    // 组件的挂载
    mountComponent(vm, el);
  }
}
